#include<iostream>
#include<pthread.h>
#include<string>
#include<unistd.h>
using namespace std;


#define TNUM 4
volatile bool quit = false;//用于让线程结束循环，退出

typedef void(*func_t)(const string& name, pthread_mutex_t* pmx, pthread_cond_t* pcd);//函数指针

class ThreadData//用于create线程是，args传参
{
public:
    ThreadData(const string& name, func_t func, pthread_mutex_t* pmx, pthread_cond_t* pcd)
    :_name(name),_func(func),_pmx(pmx),_pcd(pcd)
    {}

    string _name;//线程名
    func_t _func;//函数指针
    pthread_mutex_t* _pmx;//锁
    pthread_cond_t* _pcd;//条件变量
};

void func1(const string &name, pthread_mutex_t *pmx, pthread_cond_t *pcd)
{
    while (!quit)
    {
        pthread_mutex_lock(pmx); // 加锁
        // if(满足条件)(访问临界资源)
        // else(不满足条件，等待临界资源就绪)
        pthread_cond_wait(pcd, pmx);
        cout << name.c_str() << " is running, action : F1--帮助键" << endl;
        cout << endl;
        pthread_mutex_unlock(pmx); // 解锁
    }
}

void func2(const string &name, pthread_mutex_t *pmx, pthread_cond_t *pcd)
{

    while (!quit)
    {
        pthread_mutex_lock(pmx); // 加锁
        // if(满足条件)(访问临界资源)
        // else(不满足条件，等待临界资源就绪)
        pthread_cond_wait(pcd, pmx);
        cout << name.c_str() << " is running, action : F2--重命名" << endl;
        cout << endl;
        pthread_mutex_unlock(pmx); // 解锁
    }
}

void func3(const string &name, pthread_mutex_t *pmx, pthread_cond_t *pcd)
{

    while (!quit)
    {
        pthread_mutex_lock(pmx); // 加锁
        // if(满足条件)(访问临界资源)
        // else(不满足条件，等待临界资源就绪)
        pthread_cond_wait(pcd, pmx);
        cout << name.c_str() << " is running, action : F3--搜索按钮" << endl;
        cout << endl;
        pthread_mutex_unlock(pmx); // 解锁
    }
}

void func4(const string &name, pthread_mutex_t *pmx, pthread_cond_t *pcd)
{
    while (!quit)
    {
        pthread_mutex_lock(pmx); // 加锁
        // if(满足条件)(访问临界资源)
        // else(不满足条件，等待临界资源就绪)
        pthread_cond_wait(pcd, pmx);
        cout << name.c_str() << " is running, action : F4--浏览器网址列表" << endl;
        cout << endl;
        pthread_mutex_unlock(pmx); // 解锁
    }
}

void* Entry(void* args)
{
    //所有新线程都会执行Entry函数，在Entry函数中每个线程又会执行其对应的func
    ThreadData* td = (ThreadData*) args;
    td->_func(td->_name, td->_pmx, td->_pcd);
    sleep(1);
    cout << td->_name.c_str() <<": " <<pthread_self() << endl;
    delete td;//新线程有自己独立的栈结构，每一个td变量都在各自私有栈中保存，最后新线程运行结束时，记得释放掉申请出来的堆
    return nullptr;
}

int main()
{
    //创建并初始化锁、条件变量
    pthread_cond_t cond;
    pthread_mutex_t mutex;
    pthread_cond_init(&cond, nullptr);
    pthread_mutex_init(&mutex, nullptr);

    //创建新线程
    pthread_t tid[TNUM];
    func_t funcs[TNUM] = {func1, func2, func3, func4};
    for(int i = 0; i < TNUM; ++i)
    {
        string name = "thread";
        name += to_string(i);
        ThreadData* td = new ThreadData(name, funcs[i], &mutex, &cond);
        pthread_create(tid+i, nullptr, Entry, (void*)td);
    }

    //主线程：唤醒新线程
    int count = 10;//执行10s退出
    while(count--)
    {   
        cout << "awake thread: " << endl;
        pthread_cond_signal(&cond);//任意唤醒一个线程：并不关心具体是哪一个
        sleep(1);
    }
    
    quit = true;//此时func函数不满足条件，线程回到Entry
    cout << endl << "quit -> true." << endl;

    pthread_cond_broadcast(&cond);//虽然quit退出函数，但有线程处于等待条件状态，此处再统一唤醒。
    
    sleep(3);
    cout << endl;

    //等待新线程
    for(int i = 0; i < TNUM; ++i)
    {
        pthread_join(tid[i],nullptr);
        cout << "join thread: " << tid[i] << endl;
    }

    //销毁锁、条件变量
    pthread_cond_destroy(&cond);
    pthread_mutex_destroy(&mutex);

    return 0;
}